/*
 * By: Werner Schuster (murphee)
 * 
 * Copyright (c) 2005-2006 Werner Schuster (murphee)
 * 
 * This file is part of the EclipseShell project. EclipseShell is subject 
 * to the Eclipse Public License (EPL) available at
 * http://www.eclipse.org/org/documents/epl-v10.php
 * or in the file /epl-v10.html in the source for other info
 * see the /eclipseshell.license file
 */
package net.sf.eclipseshell.internal.actions;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import net.sf.eclipseshell.EclipseShellPlugin;
import net.sf.eclipseshell.extensions.IExecutionProviderHandle;
import net.sf.eclipseshell.internal.extensions.ExecutionProviderManager;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPersistableElement;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.IWorkbenchWindowPulldownDelegate;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.editors.text.ILocationProvider;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.FileEditorInput;

/**
 * Our sample action implements workbench action delegate.
 * The action proxy will be created by the workbench and
 * shown in the UI. When the user tries to use the action,
 * this delegate will be created and execution will be 
 * delegated to it.
 * @see IWorkbenchWindowActionDelegate
 */
public class LaunchNewShell implements IWorkbenchWindowPulldownDelegate {
	private Menu pulldownMenu_;
	private String currExtension_;
	private String currMode_;
	private IResource currentResource_;
	/**
	 * The constructor.
	 */
	public LaunchNewShell() {
	}

	/**
	 * The action has been activated. The argument of the
	 * method represents the 'real' action sitting
	 * in the workbench UI.
	 * @see IWorkbenchWindowActionDelegate#run
	 */
	public void run(IAction action) {
//		MessageDialog.openInformation(
//			window.getShell(),
//			"Interpreter Editor Plugin",
//			"Hello, Eclipse world");
//		IDE.openEditor(UIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage(), ));
		
		
		// TODO: IMPORTANT: get some kind of default value here!
		// set it in the getMenu method?
		// TODO: HACK! find some better way to create a real temporary or hidden file!
		launchEditor();
	}

	private void launchEditor() {
//		IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(System.currentTimeMillis() +"."+currExtension_));
		
		ByteArrayInputStream bais = new ByteArrayInputStream("".getBytes());
		IEditorInput inp = null; 

		if(currentResource_ == null){
			currentResource_ = ResourcesPlugin.getWorkspace().getRoot();
		}
		inp =new ShellEditorInput(currExtension_, currMode_, currentResource_);
//		}
				
		IWorkbenchWindow win = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
		try {
			IDE.openEditor(win.getActivePage(), inp, "net.sf.eclipseshell.editors.EclipseShell");
		} catch (PartInitException e) {
			EclipseShellPlugin.getDefault().log(Status.ERROR, e.getLocalizedMessage(), e);
		}
	}

	// TODO: HACK: the mode should be passed in in another way
	public class ModeFileEditorInput extends FileEditorInput {
		String mode_;
		public ModeFileEditorInput(IFile file, String mode) {
			super(file);
			mode_ = mode; 
		}
		public String getMode(){
			return mode_;
		}
	}
	
	
	public class ShellEditorInput implements IEditorInput, ILocationProvider, IStorageEditorInput {

		// TODO: override the equals method (as defined in IEditorInput)
		
		private String extensionName_;
		private String mode_;
		private IResource resource_;

		public String getExtensionName()	{
			return extensionName_;
		}
		
		public ShellEditorInput(String currExtension, String currMode, IResource currentResource) {
			this.extensionName_ = currExtension;
			this.mode_ = currMode;
			this.resource_ = currentResource_;
		}

		public IResource getResource(){
			return resource_;
		}
		
		public String getMode() {
			return mode_;
		}
		
		public boolean exists() {
			return true;
		}

		public ImageDescriptor getImageDescriptor() {
			// TODO: get the proper icon for this editor
			return ImageDescriptor.getMissingImageDescriptor();
		}

		public String getName() {
			return extensionName_;
		}

		public IPersistableElement getPersistable() {
			// TODO: this seems useful, check out how this can be applied here
			// for now, returning null is OK
			return null;
		}

		public String getToolTipText() {
			return "EclipseShell";
		}

		public Object getAdapter(Class adapter) {
			if(adapter.equals(Object.class)){
				return extensionName_;
			} if(adapter.isAssignableFrom(ILocationProvider.class)){
				return this;
			}
			// TODO Auto-generated method stub
			return null;
		}

		public IPath getPath(Object element) {
			// TODO Auto-generated method stub
			return null;
		}

		public IStorage getStorage() throws CoreException {
			return new IStorage(){

				public InputStream getContents() throws CoreException {
					ByteArrayInputStream bais = new ByteArrayInputStream("".getBytes());
					return bais;
				}

				public IPath getFullPath() {
					// TODO Auto-generated method stub
					return null;
				}

				public String getName() {
					return "Foo";
				}

				public boolean isReadOnly() {
					return false;
				}

				public Object getAdapter(Class adapter) {
					return null;
				}
				
			};

		}
		
	}
	
	/**
	 * Selection in the workbench has been changed. We 
	 * can change the state of the 'real' action here
	 * if we want, but this can only happen after 
	 * the delegate has been created.
	 * @see IWorkbenchWindowActionDelegate#selectionChanged
	 */
	public void selectionChanged(IAction action, ISelection selection) {
		if (selection instanceof IStructuredSelection) {
			IStructuredSelection strucSelection = (IStructuredSelection) selection;
			if(!strucSelection.isEmpty()){
				Object firstElement = strucSelection.getFirstElement();
				if(firstElement instanceof IResource){
					currentResource_ = (IResource) firstElement;
				}
				// TODO: probably use an adapter to get the IResource or IProject?
				if(firstElement instanceof IJavaProject){
					currentResource_ = ((IJavaProject) firstElement).getProject();
				}
			}
		}
	}

	/**
	 * We can use this method to dispose of any system
	 * resources we previously allocated.
	 * @see IWorkbenchWindowActionDelegate#dispose
	 */
	public void dispose() {
		if(pulldownMenu_ != null){
			pulldownMenu_.dispose();
		}
	}

	/**
	 * We will cache window object in order to
	 * be able to provide parent shell for the message dialog.
	 * @see IWorkbenchWindowActionDelegate#init
	 */
	public void init(IWorkbenchWindow window) {
		IExecutionProviderHandle[] provs = ExecutionProviderManager.getAllProviders();
		// set the default extension
		if(provs.length > 0){
			String[] extensions = provs[0].getFileExtensions();
			if(extensions.length > 0){
				currExtension_ = extensions[0];
			}
		}
	}

	public Menu getMenu(Control parent) {
		if (pulldownMenu_ == null) {
			pulldownMenu_= new Menu(parent);	
			IExecutionProviderHandle[] provs = ExecutionProviderManager.getAllProviders();
//			// set the default extension
//			if(provs.length > 0){
//				String[] extensions = provs[0].getFileExtensions();
//				if(extensions.length > 0){
//					currExtension_ = extensions[0];
//				}
//			}
			// setup the menu
			for (int i= 0; i < provs.length; i++) {
				MenuItem item = new MenuItem(pulldownMenu_, SWT.CASCADE);
				item.setText(provs[i].getDisplayName());
				
				// menuData == {fileExtension, supportedRunMode}
				String[] menuData = new String[2];
				menuData[0] = provs[i].getFileExtensions()[0];

				
				String[] supportedRunModes = provs[i].getSupportedRunModes();

				
				if(supportedRunModes.length > 0){
					Menu currCascadingMenu = new Menu(item);
					for (int j = 0; j < supportedRunModes.length; j++) {
						String currMode = supportedRunModes[j];
						MenuItem cascadingItem = new MenuItem(currCascadingMenu, SWT.DEFAULT|SWT.CASCADE);
						cascadingItem.setText(provs[i].getDisplayName() + ":"+ currMode);
						String[] currentMenuData = new String[2];
						currentMenuData[0] = provs[i].getFileExtensions()[0];
						currentMenuData[1] = currMode;
						cascadingItem.setData(currentMenuData);
						hookupSelectionListener(cascadingItem);
					}
					item.setMenu(currCascadingMenu);
					
					menuData[1] = supportedRunModes[0];
					item.setData(menuData);
				} else {
					item.setData(menuData);
					hookupSelectionListener(item);
				}

				
				// TODO: HACK: find some better way to do a pulldown menu!
			}			
		
		}
		return pulldownMenu_;		
	}

	private void hookupSelectionListener(MenuItem item) {
		item.addSelectionListener(new SelectionListener(){
			public void widgetSelected(SelectionEvent e) {
				if (e.getSource() instanceof MenuItem) {
					MenuItem item = (MenuItem) e.getSource();
					Object data = item.getData();
					if (data instanceof String[]) {
						String[] extensionAndMode = (String[]) data;
						currExtension_ = extensionAndMode[0];
						currMode_ = extensionAndMode[1];
						launchEditor();
						// TODO: launch here!
					}
				}
			}

			public void widgetDefaultSelected(SelectionEvent e) {
				if (e.getSource() instanceof MenuItem) {
					MenuItem item = (MenuItem) e.getSource();
				}
			}
			
		});
	}

	
	
}